18.4 ヒープのスナップショットの撮影
併合型参照カウント法は
ポインタの書き込みのあったオブジェクトの現在のバージョンをつかってインクリメント
ポインタの書き込みのあったオブジェクトの複製を使って参照カウントをデクリメント
参照カウント操作を行うスレッドをミューテータと並行に実行する方法を考える
ミューテータスレッドはどれも、スレッドのバッファをコレクタに転送する間、一時的に停止させられる
ただし、すべてのミューテータスレッドがバッファを転送し終えさえすればそれらは再開させることができる
デクリメントは簡単
ログ内の複製を使うだけ
インクリメントはログが転送された時点のオブジェクトを使う
ログが転送されてからインクリメントするまでに再度書き込みがなかった場合(cleanだった場合)
現在のオブジェクトのコピーを使う
ログが転送されてからインクリメントするまでに再度書き込みがあった場合(dirtyだった場合)
cleanから再度dirtyになったのでどこかのスレッドのログにオブジェクトの複製がある
それを探してインクリメントに使う
code:algorithm-18-5.py
def incrementNew(entry): # コレクタのログ内のエントリを使用
obj ← objFromLog(entry) # 現在のオブジェクト
if not dirty(obj)
# 1 ここでdirtyになった場合replicaがdirty
replica ← copy(obj) # オブジェクトの参照スロット群をコピー
# 2 ここでdirtyになった場合replicaはdirtyではない
if dirty(obj) # TODO: これ意味ある?
replica ← getLogPointer(obj) # あるスレッドのログ内のエントリ
else
replica ← getLogPointer(obj)
# if not dirty(obj):
# replica ← copy(obj)
# if dirty(obj)
# replica ← getLogPointer(obj)
for each fld in Pointers(replica)
child ← *fld
if child ≠ null
rc(child) ← rc(child) + 1
mark(child) # もし年少世代を追跡するなら
動作の図
https://gyazo.com/f6c75f79ee8307b738a43c22a3596f83
dirtyだったときの再取得をやめる
collect 1回目
Aのreplicaを使ってDの参照カウントを +1する
collect2回目
ログ(A.f = D) を見てDの参照カウントを +1する